<template>
  <div ref="display"></div>
</template>

<script>
import Vue from "vue";
import { genRandomStr } from "@/utils/tool";
export default {
  props: {
    code: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      component: null,
      html: "",
      js: "",
      css: "",
      id: genRandomStr(),
    };
  },
  // watch: {
  //   code(val) {
  //     this.destroyCode();
  //     this.renderCode();
  //   },
  // },
  mounted() {
    this.renderCode();
  },
  beforeDestroy() {
    this.destroyCode();
  },
  methods: {
    // 解析 code
    getSource(source, type) {
      const regex = new RegExp(`<${type}[^>]*>`);
      let openingTag = source.match(regex);
      if (!openingTag) {
        return "";
      } else {
        openingTag = openingTag[0];
        return source.slice(
          source.indexOf(openingTag) + openingTag.length,
          source.lastIndexOf(`</${type}>`)
        );
      }
    },
    // 切割 code
    splitCode() {
      if (!this.code) return;
      const script = this.getSource(this.code, "script").replace(
        /export default/,
        "return"
      );
      this.js = script;
      const css = this.getSource(this.code, "style");
      this.css = css;
      const template = `<div id="app">${this.getSource(
        this.code,
        "template"
      )}</div>`;
      this.html = template;
    },
    // 渲染 code
    renderCode() {
      this.splitCode();
      if (this.html !== "" || this.js !== "") {
        const parseStrToFunc = new Function(this.js)();
        parseStrToFunc.template = this.html;
        const Component = Vue.extend(parseStrToFunc);
        this.component = new Component().$mount();
        this.$refs.display.appendChild(this.component.$el);
      }
      if (this.css !== "") {
        const style = document.createElement("style");
        style.type = "text/css";
        style.id = this.id;
        style.innerHTML = this.css;
        document.getElementsByTagName("head")[0].appendChild(style);
      }
    },
    // 销毁 code
    destroyCode() {
      const $target = document.getElementById(this.id);
      if ($target) {
        $target.parentNode.removeChild($target);
      }
      if (this.component) {
        this.$refs.display.removeChild(this.component.$el);
        this.component.$destroy();
        this.component = null;
      }
    },
  },
};
</script>
